package com.gitee.elf.core.entity.trait

import com.gitee.elf.api.annotation.Id
import com.gitee.elf.core.entity.EntityInstance
import com.gitee.elf.core.entity.ProxyEntity
import org.bukkit.Bukkit
import taboolib.common.LifeCycle
import taboolib.common.inject.ClassVisitor
import taboolib.library.reflex.Reflex.Companion.invokeConstructor
import taboolib.module.nms.MinecraftVersion
import java.util.function.Supplier
import kotlin.reflect.KClass

interface Trait {

    companion object {

        val traits = mutableMapOf<String, Class<Trait>>()

        val plugins = mutableMapOf<String, Boolean>()

        fun createTraits(instance: EntityInstance): Map<String, Trait> {
            val mapOf = mutableMapOf<String, Trait>()
            traits.forEach { id, clazz ->
                if (clazz.isAnnotationPresent(VersionRestrict::class.java)) {
                    val versions = clazz.getAnnotation(VersionRestrict::class.java).values
                    if (MinecraftVersion.major.toString() !in versions) {
                        return@forEach
                    }
                }
                if (clazz.isAnnotationPresent(EntityRestrict::class.java)) {
                    val entities = clazz.getAnnotation(EntityRestrict::class.java).values.map { it.java }
                    if (instance.mapping!! !in entities) {
                        return@forEach
                    }
                }
                if (clazz.isAnnotationPresent(PluginRestrict::class.java)) {
                    if (!isPluginEnable(clazz.getAnnotation(PluginRestrict::class.java).value)) {
                        return@forEach
                    }
                }
                mapOf[id] = clazz.invokeConstructor(instance)
            }
            return mapOf
        }

        fun isPluginEnable(name: String): Boolean {
            return plugins.computeIfAbsent(name) {
                Bukkit.getPluginManager().isPluginEnabled(name)
            }
        }

    }

    class Visitor : ClassVisitor(0) {

        override fun getLifeCycle(): LifeCycle {
            return LifeCycle.LOAD
        }

        @Suppress("UNCHECKED_CAST")
        override fun visitStart(clazz: Class<*>, instance: Supplier<*>?) {
            if (Trait::class.java.isAssignableFrom(clazz) && clazz.isAnnotationPresent(Id::class.java)) {
                val id = clazz.getAnnotation(Id::class.java)!!.value
                traits[id] = clazz as Class<Trait>
            }
        }

    }

    annotation class PluginRestrict(val value: String)

    annotation class VersionRestrict(val values: Array<String>)

    annotation class EntityRestrict(val values: Array<KClass<ProxyEntity<*>>>)

}